<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BDataObjWithGroup
 *
 * @author I062261
 */
abstract class BEntityWithGroup extends BEntity {

    protected $groups;
    public $defaultGroup = null;

    public function getGroups($context = NULL, $recursive = FALSE) {

        $groupClass = get_class($this) . 'Group';
        $groupContext = null;
        $parent = NULL;
        if ($context != NULL) {
            if (is_string($context)) {
                $groupClass = $context;
                $groupContext = new $groupClass();
            }
            if ($context instanceof BGroup) {
                $groupContext = $context;
                $groupClass = get_class($groupContext);
            }
            /*
              if (is_array($context)) {
              if (isset($context['groupClass'])) {
              $groupClass = $context['groupClass'];
              unset($context['groupClass']);
              }
              $groupContext = new $groupClass();
              foreach ($context as $name => $value) {
              if (property_exists($groupClass, $name)) {
              $groupContext->$name = $value;
              }
              }
              }
             * 
             */
        }

        if ($groupContext == NULL)
            $groupContext = new $groupClass();

        $groupRowContext = NULL;
        if ($groupContext instanceof BGroup)
            $groupRowContext = $groupContext->getRepository()->getRow();

        $groupRows = $this->getRepository()->getRow()->getGroups($groupRowContext);

        $groupList = array();

        foreach ($groupRows as $row) {
            $group = new $groupClass();
            $group->getRepository()->loadEntity($row);
            $groupList[$group->getId()] = $group;
        }

        if (is_array($context)) {
            if (isset($context['parent']) && $context['parent'] != NULL) {
                $parent = $context['parent'];
                if (is_string($parent)) {
                    $parent = $groupClass::find($parent);
                }
                if ($parent instanceof $groupClass) {
                    foreach ($groupList as $key => $group) {
                        if (!$group->isChildOf($parent, TRUE)) {
                            unset($groupList[$key]);
                        }
                    }
                }
            }
        }



        return $groupList;

        /*

          if (!$context instanceof BGroup) {
          $groupClass = $this->getGroupClass();
          if (is_array($context)) {
          if (isset($context['groupClass']) && $context['groupClass'] != NULL)
          $groupClass = $context['groupClass'];
          if (!isset($context['classname']))
          $context['classname'] = $groupClass;
          }
          $context = $groupClass::getEntityContext($context);
          }

          $repository = $this->getRepository();
          $repository->setModel($this->getModelClassAsGroupMember());
          $view = $repository->getView(array('memberId' => $this->getId()));

          $groups = BRepositoryFactory::createRepository2()->findMemberGroups($this, $context);

          if ($groups != NULL && $recursive) {
          $recursiveItems = $groups;
          foreach ($groups as $group) {
          if ($group instanceof BTreeEntity) {
          $parentGroups = $group->getParent($recursive);
          foreach ($parentGroups as $item) {
          if ($item->getId() !== 1)//ignore root node
          $recursiveItems[$item->getId()] = $item;
          }
          }
          }
          if ($recursiveItems != NULL) {
          return $recursiveItems;
          }
          }

          if ($groups != NULL) {
          foreach ($groups as $key => $item)
          if ($item->getName() === 'root')//ignore root node
          unset($groups[$key]);
          return $groups;
          }
         * 
         */
    }

    /**
     * 
     * @param type $context
     * @return BGroup
     */
    public function getGroup($context = NULL) {

        $isDefaultGroup = FALSE;
        //get default group
        if ($context == NULL) {
            if ($this->defaultGroup != null)
                return $this->defaultGroup;
            $groupClass = $this->getGroupClass();
            $context = new $groupClass();
            $isDefaultGroup = TRUE;
        }

        $groups = $this->getGroups($context);

        if ($groups == NULL || count($groups) < 1)
            return array();

        if (count($groups) > 1) {
            if (is_string($context)) {
                foreach ($groups as $group) {
                    if ($group->getName() == $context)
                        return $group;
                }
            }

            if (is_array($context)) {
                if (isset($context['parent']) && $context['parent'] != NULL) {
                    $parent = $context['parent'];

                    foreach ($groups as $group) {
                        if (is_string($parent)) {
                            $class = get_class($group);
                            $parent = $class::find($parent);
                        }
                        if ($parent instanceof BGroup) {
                            if ($parent->isParentOf($group))
                                return $group;
                        }
                    }
                }
            }
        }

        return reset($groups);
        /*


          if ($groups != NULL) {
          $finalGroups = array();
          foreach ($groups as $id => $group) {
          $groupClass = get_class($group);
          if ($groupClass::filterEntityByContext($group, $context))
          $finalGroups[$id] = $group;
          }
          $group = reset($finalGroups);
          }
          if ($isDefaultGroup && $group != NULL)
          $this->defaultGroup = $group;
          return $group;
         * 
         */
    }

    /**
     * 
     * @param type $context, should contain group id or group name, group name 
     * can be a nested group name
     * @return boolean
     */
    public function addGroup($context) {

        $context = BRepository::getContext($context);

//$mClass = $context->modelClass;
        $groupClass = $context->groupClass;

        $parentGroup = $groupClass::find($context);

        if ($parentGroup instanceof BGroup)
            return $parentGroup->addMember($this);

        return FALSE;
    }

    public function addNestedConfig($nestedGroupMembers, $parentGroup = NULL) {
        if ($parentGroup == NULL)
            $parentGroup = $this->getGroup(array('name' => BGroup::node_root));
        foreach ($nestedGroupMembers as $name => $value) {
            if (is_array($value)) {
                $parentGroup = $parentGroup->addChild(array('name' => $name));
                $this->addNestedConfig($value, $parentGroup);
            }
            if (is_string($value)) {
                $parentGroup = $parentGroup->addChild(array('name' => $name));
                $parentGroup->addMember(array('name' => $value));
            }
        }
    }

    /**
     * format:
     * 1.find by name and group name, for example:a,  a.b.c , a|b|c
     * 2.$context may contain other attributes, pass to dataobj to find if no group
     * if have group, pass to group class for finding
     * @param type $context
     * @return boolean
     */
    public static function find($context, $entity = NULL) {

        $all = self::findAll($context, $entity);

        if ($all != NULL)
            return reset($all);

        return FALSE;
    }

    public static function findAll($context = null, $entity = NULL) {

        $memberClass = get_called_class();
        $memberContext = NULL;
        $group = NULL;

        //find all by type
        if (is_array($context) && isset($context['type'])) {

            $type = $context['type'];
            $typeGroup = NULL;

            if ($entity == NULL) {
                $class = get_called_class();
                $entity = new $class();
            }

            if (is_string($type)) {
                $context = array();
                $context['parent'] = $type;
                $typeGroup = $entity->getGroup($context);
                if (!$typeGroup instanceof BGroup) {
                    $context['parent'] = 'type.' . $type;
                    $typeGroup = $entity->getGroup($context);
                }
            }

            if ($type instanceof BGroup) {
                $typeGroup = $type;
            }

            if ($typeGroup instanceof BGroup) {
                $memberList = $typeGroup->getMembers($entity);
                if ($memberList == NULL)
                    $memberList = array();
                return $memberList;
            }
        }

        //support array parameter
        if (is_array($context) && $context != NULL) {
            //$memberContext = new $memberClass();

            if (isset($context['group'])) {
                $group = $context['group'];
                unset($context['group']);
            }
        }

        //support nest name
        if (is_string($context)) {
            $memberContext = new $memberClass();
            $name = $context;
            //for user, do not match
            //if (!$memberContext instanceof BUser) {
            $names = preg_split(BTreeEntity::Pattern_Delimiter, $name);
            $count = count($names);
            $memberName = end($names);
            if ($count > 1) {
                $groupName = preg_replace("/" . $memberName . "/", '', $name);
                $groupClass = get_class($this) . 'Group';
                $group = $groupClass::find($groupName);
            }
            $memberContext->name = $memberName;
            //}
        }

        if ($group != NULL && $group instanceof BGroup) {
            return $group->getMembers($memberContext);
        }

        //default, find by member context
        return parent::findAll($context);
    }

    public function save($context = null) {

        //$context = BRepository::getContext($context, $this);
        $entityContext = self::getEntityContext($context, $this);
        $groupContext = self::getGroupContext($context, $this);

        if ($this->id == NULL) {
            $newId = parent::save($entityContext);
            $this->id = $newId;
        } else {
            parent::save($entityContext);
        }

        if ($groupContext != NULL) {
            $groupClass = $this->getGroupClass();
            $group = $groupClass::find($groupContext);
            if ($group instanceof BGroup) {
                $group->addMember($this);
            }
        }

        return $this->id;
    }

    public function isMemberOf($group) {

        if ($group instanceof BGroup) {

            $class = get_class($group);
            $context = new $class();
            //$context['groupClass'] = get_class($group);
            if (isset($group->spaceId) && $group->spaceId != NULL && $group->spaceId != 0)
                $context->spaceId = $group->spaceId;
            if (isset($group->appId) && $group->appId != NULL && $group->appId != 0)
                $context->appId = $group->appId;
            $groups = $this->getGroups($context);

            foreach ($groups as $item) {
                if ($item instanceof BGroup)
                    if ($item->id == $group->id || $item->isChildOf($group))
                        return TRUE;
            }
        }

        return FALSE;
    }

    //get default group classname
    public function getGroupClass($data = NULL) {
        $class = get_class($this);
        if (preg_match("/Member$/", $class))
            return preg_replace("/Member/", "", $class);
        else
            return $class . 'Group';
    }

    public function getModelClassAsGroupMember($data = NULL) {
        if ($data instanceof BGroup)
            $group = $data;
        else
            $group = $this->getGroup();

        if ($data)
            if ($group instanceof BSGroup) {
                return $group->getMemberModelClass();
            } else if ($group instanceof BGroup) {
                $groupClass = get_class($group);
            }

        if (is_string($group))
            $groupClass = $group;

        if (preg_match("/Group$/", $groupClass))
            $groupMemberClass = $groupClass . 'Member';
        else {
            $memberClass = get_class($this);
            $groupMemberClass = $groupClass . preg_replace("/^B/", "", $memberClass);
        }

        $mClass = preg_replace("/^B/", "BM", $groupMemberClass);
        return $mClass;
    }

    public static function getGroupContext($data, $entityContext = NULL) {

        $name = NULL;
        $groupContext = NULL;

        if ($data instanceof BEntityWithGroup)
            $name = $data->name;

        if (is_string($data))
            $name = $data;

        if (is_array($data)) {
            if (isset($data['name']) && $data['name'] != NULL)
                $name = $data['name'];
        }

        $names = preg_split('[' . BTreeEntity::delimiter . ']', $name);
        $count = count($names);
        if ($count > 1) {
            $class = get_called_class();

            $groupClass = NULL;

            if ($entityContext == NULL)
                $entityContext = new $class();

            if ($data instanceof BEntityWithGroup)
                $entityContext = $data;

            if (is_array($data) && isset($data['groupClass'])) {
                $groupClass = $data['groupClass'];
                $groupContext = new $groupClass();
            }

            if (is_array($data) && isset($data['groupContext']))
                $groupContext = $data['groupContext'];

            if ($groupContext == NULL) {
                if ($entityContext instanceof BEntityWithGroup) {
                    $groupClass = $entityContext->getGroupClass();
                    $groupContext = new $groupClass();
                }
            }
            $lastName = end($names);
            $groupName = preg_replace("/" . $lastName . "$/", '', $name);
            $groupContext->name = $groupName;
        }

        return $groupContext;
    }

    public static function getEntityContext($data, $entityContext = NULL) {
        $groupContext = self::getGroupContext($data, $entityContext);

        if ($groupContext != NULL) {
            $name = NULL;
            if (is_string($data))
                $name = $data;
            if (is_array($data) && isset($data['name']))
                $name = $data['name'];
            if ($data instanceof BEntityWithGroup)
                $name = $data->name;

            $names = preg_split('[' . BTreeEntity::delimiter . ']', $name);

            $entityName = end($names);

            if (is_array($data))
                $data->name = $entityName;

            if (is_string($data))
                $data = $entityName;

            if ($data instanceof BEntity)
                $data->name = $entityName;
        }

        return parent::getEntityContext($data, $entityContext);
    }

    public function addType($type) {
        $groupClass = get_class($this) . 'Group';
        if (class_exists($groupClass)) {
            if (is_string($type)) {
                if (strpos($type, $groupClass::Type_Group . '.') == FALSE) {
                    $type = $groupClass::Type_Group . '.' . $type;
                }
                $typeGroup = $groupClass::find($type);
                if (!$typeGroup instanceof $groupClass) {
                    $groupClass::getRoot()->addChild($type);
                }
            }
            if ($type instanceof $groupClass) {
                $type->addMember($this);
            }
        }
    }

    public function getTypeList($data = NULL) {
        $list = array();
        $groupClass = get_class($this) . 'Group';
        if (class_exists($groupClass)) {
            $allTypes = $groupClass::getRoot()->getChildrenAsLeaf(NULL, TRUE);
            foreach ($allTypes as $id => $type) {
                if ($this->isMemberOf($type))
                    $list[$id] = $type;
            }
        }
        return $list;
    }

    public function haveType($type) {
        $groupClass = get_class($this) . 'Group';
        if (class_exists($groupClass)) {
            if (is_string($type)) {
                if (strpos($type, $groupClass::Type_Group . '.') != FALSE) {
                    $type = $groupClass::Type_Group . '.' . $type;
                    $type = $groupClass::find($type);
                }
            }
            if ($type instanceof $groupClass) {
                if ($type->haveMember($this))
                    return TRUE;
            }
        }

        return FALSE;
    }

    /**
     * 取type的规则：
     * 比如定义的type 
     * $event->addType('promotion.furniture')
     * $event->addType('promotion.computer')
     * then 
     * $event->getType() return $type of promotion
     * $event->getType('promotion') return type of promotion
     * $event->getType('promotion.') return type of furniture or computer
     * $event->getType('promotion.computer') return type of promotion.computer
     * $event->getType(array('parent'=>'promotion')) return type of promotion.furniture or promotion.furniture
     * @param BGroup $data
     * @return type
     */
    public function getType($data = NULL) {
        $allTypes = $this->getTypeList();
        $typeList = array();
        if (is_string($data)) {
            foreach ($allTypes as $id => $type) {
                if (isset($type->name)) {
                    $name = $type->getFullName();
                    if (strpos($data, $name) != FALSE)
                        return $type;
                    else {
                        if (strpos($name, BGroup::Type_Group . '.' . $data) != FALSE) {
                            return $type;
                        }
                    }
                }
            }
        }
        if (is_array($data)) {
            $parent = isset($data['parent']) ? $data['parent'] : NULL;
            if ($parent != NULL) {
                if (is_string($parent)) {
                    $parent = $this->getGroup($parent);
                }
                if ($parent instanceof BGroup) {
                    foreach ($allTypes as $type) {
                        if ($parent->isParentOf($type))
                            return $type;
                    }
                }
            }
        }

        if ($data instanceof BGroup) {
            if (isset($data->name)) {
                $tName = $data->name;
                foreach ($allTypes as $id => $type) {
                    if (isset($type->name)) {
                        $name = $type->name;
                        if (strpos($tName, $name) != FALSE)
                            return $type;
                    }
                }
            }
        }
        return reset($allTypes);
    }

    public function getGroupMemberModelClass($groupData = NULL) {
        $class = get_class($this);
        //default groupClass
        $groupClass = $class . 'Group';
        if (is_string($groupData) && $groupData != NULL) {
            $groupClass = $groupData;
        }
        if ($groupData instanceof BGroup)
            $groupClass = get_class($groupData);
    }

}

?>
